package com.apes.framework.util.statistics;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.apes.framework.config.elasticsearch.ApesElasticsearchHealthIndicator;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.plugin.event.Listener;
import com.apes.framework.rop.event.RopListener;
import com.apes.framework.rop.session.SimpleSession;
import com.apes.framework.util.DateUtil;
import com.apes.framework.util.EventUtil;
import com.apes.framework.util.MapUtil;
import com.apes.framework.util.NetUtil;
import com.apes.oap.event.AfterDoServiceEvent;
import com.apes.oap.event.RopEventListener;
import com.apes.oap.response.OapResponse;
import com.apes.oap.session.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.actuate.health.Status;
import org.springframework.util.StringUtils;

import java.net.URLDecoder;

/**
 * 功能：
 *
 * @author xul
 * @create 2017-12-18 18:51
 */
@RopListener
public class AfterDoServiceListener implements RopEventListener<AfterDoServiceEvent> {
    private Logger logger = LoggerFactory.getLogger(AfterDoServiceListener.class);

    @Value("${logger.statistics.filters:find,query}")
    private String filters;

    @Value("${rocketmq.tags:}")
    private String tags;

    @Autowired
    private StatisticsRepository repository;

    private ApesElasticsearchHealthIndicator healthIndicator;

    public AfterDoServiceListener(ApesElasticsearchHealthIndicator healthIndicator) {
        this.healthIndicator = healthIndicator;
    }

    /**
     * 响应事件
     *
     * @param ropEvent
     */
    @Override
    public void onRopEvent(AfterDoServiceEvent ropEvent) {
        Statistics statistics = new Statistics();
        statistics.setServer(NetUtil.getServerIp());
        statistics.setTags(tags);
        statistics.setMethod(ropEvent.getRopRequestContext().getMethod());
        statistics.setVersion(ropEvent.getRopRequestContext().getVersion());
        statistics.setAppKey(ropEvent.getRopRequestContext().getAppKey());
        statistics.setSessionId(ropEvent.getRopRequestContext().getSessionId());
        statistics.setIp(ropEvent.getRopRequestContext().getIp());
        statistics.setBeginTime(DateUtil.timeStampToStr(ropEvent.getServiceBeginTime()));
        statistics.setEndTime(DateUtil.timeStampToStr(ropEvent.getServiceEndTime()));
        statistics.setTime(ropEvent.getServiceEndTime() - ropEvent.getServiceBeginTime());
        statistics.setRequest(JSON.toJSONString(ropEvent.getRopRequestContext().getAllParams()));
        if (!filter(ropEvent.getRopRequestContext().getMethod())) {
            statistics.setResponse(JSON.toJSONString(ropEvent.getRopRequestContext().getRopResponse()));
        }
        Session session = ropEvent.getRopRequestContext().getSession();
        if (session != null) {
            statistics.setUserId(((SimpleSession) session).getUserId());
            statistics.setPostId(((SimpleSession) session).getPostId());
        }

        addInvokeMethod(statistics);
        save(statistics);

        if (ropEvent.getRopRequestContext().getRopResponse() instanceof OapResponse) {
            OapResponse response = (OapResponse) ropEvent.getRopRequestContext().getRopResponse();
            if (!response.getHeader().getCode().equals("success")) {
                EventUtil.sendAynEvent(this, "event:invoke.exception.intercept",
                        MapUtil.mapper("topic", ropEvent.getRopRequestContext().getMethod(),
                                "type", "ESB",
                                "request", statistics.getRequest(),
                                "response", statistics.getResponse()));
            }
        }
    }

    private void save(Statistics statistics) {
        boolean health = healthIndicator != null ? healthIndicator.health().getStatus() == Status.UP : false;
        if (health) {
            repository.save(statistics);
        } else {
            EventUtil.sendSynEvent(this, "event:log.message.publish", statistics);
        }
    }

    @Listener(topic = "event:log.message.consume")
    public void consume(SimpleRequest request) {
        Statistics statistics = request.getO(Statistics.class);
        repository.save(statistics);
    }

    private boolean filter(String method) {
        String[] filters = this.filters.split(",");
        for (String filter : filters) {
            if (method.indexOf(filter.trim()) != -1) return true;
        }
        return false;
    }

    /**
     * 调用的方法是 PI 的时候, 将真实的调用方法存入，方便与查询
     * {"body": {} , "header": { "method" : ""}}   PI 调用
     * {"interfaceMethod": method, "pdata": {}}    通过 report.interface 调用老框架
     *
     * @param statistics 参数
     */
    private void addInvokeMethod(Statistics statistics) {
        String method = statistics.getMethod().toUpperCase();
        if (method.startsWith("PI.")) {
            JSONObject body = JSONObject.parseObject(statistics.getRequest());
            if (StringUtils.isEmpty(body.getString("body"))) return;
            JSONObject params = JSONObject.parseObject(body.getString("body"));
            if (params.containsKey("body") && params.containsKey("headers")) {
                JSONObject headers = params.getJSONObject("headers");
                String invokeMethod = headers.getString("method");
                statistics.setInvokeMethod(invokeMethod);

                // 处理APP调用 urlEncode 转义
                try {
                    if ("get".equals(headers.getString("action"))) {
                        JSONObject bodyData = params.getJSONObject("body");
                        String query = bodyData.getString("query");

                        String queryDecoder = URLDecoder.decode(query, "UTF-8");
                        statistics.setQueryDecoder(queryDecoder);
                    }
                } catch (Exception e) {
                    // 转义报错不做处理
                }
            }
        }

        if (method.startsWith("REPORT.")) {
            JSONObject body = JSONObject.parseObject(statistics.getRequest());
            JSONObject params = JSONObject.parseObject(body.getString("body"));
            String invokeMethod = params.getString("interfaceMethod");
            statistics.setInvokeMethod(invokeMethod);
        }
    }


    /**
     * 执行的顺序号
     *
     * @return
     */
    @Override
    public int getOrder() {
        return 100;
    }
}
